{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# `Nuqleon.Linq.Expressions.Optimizers`\n",
        "\n",
        "Provides optimizers for expression trees."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Reference the library"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Option 1 - Use a local build\n",
        "\n",
        "If you have built the library locally, run the following cell to load the latest build."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "#r \"bin/Debug/net6.0/Nuqleon.Linq.Expressions.Optimizers.dll\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Option 2 - Use NuGet packages\n",
        "\n",
        "If you want to use the latest published package from NuGet, run the following cell."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "#r \"nuget:Nuqleon.Linq.Expressions.Optimizers,*-*\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## (Optional) Attach a debugger\n",
        "\n",
        "If you'd like to step through the source code of the library while running samples, run the following cell, and follow instructions to start a debugger (e.g. Visual Studio). Navigate to the source code of the library to set breakpoints."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "System.Diagnostics.Debugger.Launch();"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## `ExpressionOptimizer`\n",
        "\n",
        "The `ExpressionOptimizer` class is an expression tree visitor that rewrites an expression tree by performing various types of optimizations that can be configured by the user.\n",
        "\n",
        "Optimizers can come in handy to reduce the size and evaluation complexity at runtime. For example, in the context of Reaqtor expression trees get serialized, sent across cients and services, get stored in databases, and parts of them get evaluated for many events. Therefore, it makes sense to optimize expressions in many ways:\n",
        "\n",
        "* Reduce the size, to make I/O more efficient.\n",
        "* Reduce runtime overheads, including:\n",
        "  * CPU time to evaluate expressions;\n",
        "  * Memory allocations.\n",
        "\n",
        "As an example, consider a query like this:\n",
        "\n",
        "```csharp\n",
        "Task CreateWeatherSubscription(ClientContext ctx, string city)\n",
        "{\n",
        "    return ctx.GetObservable<WeatherInfo>(weatherUri).Where(x => x.City.ToLower() == city.ToLower()).SubscribeAsync(subUri, observer);\n",
        "}\n",
        "```\n",
        "\n",
        "where we omitted some details. Upon submitting this query to the service, we'll inline the value of `city` in the query, resulting in a query of the following form:\n",
        "\n",
        "```csharp\n",
        "weather.Where(x => x.City.ToLower() == \"Seattle\".ToLower())\n",
        "```\n",
        "\n",
        "Note that this query would evaluate `\"Seattle\".ToLower()` for every weather event received on the stream. This has both CPU and memory costs. It'd be nice if the expression got optimized to:\n",
        "\n",
        "```csharp\n",
        "weather.Where(x => x.City.ToLower() == \"seattle\")\n",
        "```\n",
        "\n",
        "This, and much more, is what the expression optimizer can achieve. Let's have a look."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To create an optimizer instance, the constructor accepts two parameters:\n",
        "\n",
        "* `ISemanticProvider` to specify a semantic provider that's consulted by the optimizer to make optimization decisions;\n",
        "* `IEvaluatorFactory` to control the behavior of partial evaluation of subtrees."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can have a first look at the optimizer by providing defaults for these parameters. In subsequent paragraphs of the notebook we'll get to the next level of detail."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "using System.Linq.Expressions;\n",
        "\n",
        "var sem = new DefaultSemanticProvider();\n",
        "var eval = new DefaultEvaluatorFactory();\n",
        "\n",
        "var opt = new ExpressionOptimizer(sem, eval);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To illustrate optimizations, let's first craft an expression by hand."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "(1 + 2)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var expr = Expression.Add(Expression.Constant(1), Expression.Constant(2));\n",
        "\n",
        "Console.WriteLine(expr);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Obviously, we can perform constant folding on this expression to reduce it to a single `ConstantExpression` node whose value is `3`. By running the optimizer's `Visit` method, we get exactly that result."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var optimized = opt.Visit(expr);\n",
        "\n",
        "Console.WriteLine(optimized);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "What about a more complex expression that involves method calls and whatnot? An example is shown below, this time using `Expression<T>` language support to construct such an expression."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => \"foobarqux\".ToUpper().Substring(2, Parse(\"3\"))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => \"foobarqux\".ToUpper().Substring(2, 3)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<string>> f = () => \"foobarqux\".ToUpper().Substring(2, int.Parse(\"3\"));\n",
        "\n",
        "Console.WriteLine(f);\n",
        "\n",
        "var optimized = opt.Visit(f);\n",
        "\n",
        "Console.WriteLine(optimized);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This time, nothing happens, because the default semantic provider does not supply information about the purity of methods that enables it to perform evaluation of these subexpressions during optimization. To achieve this, we can zoom in to the semantic provider a tiny bit."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "False\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var intParseMethod = typeof(int).GetMethod(nameof(int.Parse), new[] { typeof(string) });\n",
        "\n",
        "Console.WriteLine(sem.IsPure(intParseMethod));"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The optimizer talks to the semantic provider to ask questions like `IsPure(expr)` to check whether an expression is pure. There are many more questions it can ask, which we shown below by just dumping the interface's members."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "AllBitsOne\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "AllBitsZero\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "AlwaysThrows\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "GetConstantValue\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "HasConstantValue\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsAlwaysNull\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsConst\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsFalse\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsIdentityFunction\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsImmutable\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsMaxValue\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsMinValue\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsNeverNull\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsOne\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsPure\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsTrue\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "IsZero\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "NeverThrows\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "foreach (var m in typeof(ISemanticProvider).GetMethods().Select(m => m.Name).Distinct().OrderBy(m => m))\n",
        "{\n",
        "    Console.WriteLine(m);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "How can we teach the semantic provider that `int.Parse(string)` is pure so an optimizer can perform partial evaluation?"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Building a simple custom semantic provider\n",
        "\n",
        "One option is to inherit from `DefaultSemanticProvider` and override the method."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "using System.Reflection;\n",
        "\n",
        "class MySemanticProvider : DefaultSemanticProvider\n",
        "{\n",
        "    public override bool IsPure(MemberInfo member)\n",
        "    {\n",
        "        return base.IsPure(member) || member == typeof(int).GetMethod(nameof(int.Parse), new[] { typeof(string) });\n",
        "    }\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Later, we'll see how this can be made easier by building catalogs. For now, let's stick with this approach and create a new optimizer instance using the semantic provider shown above."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var sem = new MySemanticProvider();\n",
        "var eval = new DefaultEvaluatorFactory();\n",
        "\n",
        "var opt = new ExpressionOptimizer(sem, eval);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "If we run this optimizer over our expression, we get a different result."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => \"foobarqux\".ToUpper().Substring(2, Parse(\"3\"))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => \"foobarqux\".ToUpper().Substring(2, 3)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Console.WriteLine(f);\n",
        "\n",
        "var optimized = opt.Visit(f);\n",
        "\n",
        "Console.WriteLine(optimized);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Note that `int.Parse(\"3\")` was evaluated to `3`.\n",
        "\n",
        "> **Note:** The attentive reader will remark that `int.Parse(string)` is not pure, because it depends on the current culture. However, if an environment is configured in such a way that the result is predictable, e.g. the expression is optimized in the same environment where it is being evaluated, the optimization is valid. The extensible nature of semantic providers enables to make this type of choices."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "It goes without saying that having to implement all of these purity checks can get cumbersome really fast. There are tons of members in the .NET Framework that have specific characteristics such as purity (but, as we will learn later, there are many other semantic questions). For example, we'd have to list `Substring` and `ToUpper` as pure. Luckily, there's a notion of catalogs."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Using built-in catalogs\n",
        "\n",
        "This library ships with a set of catalogs for commonly used semantic questions. An example is the `PureMemberCatalog`, which is shown below for the `System.String` type."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Void .ctor(Char[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Void .ctor(Char[], Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Void .ctor(Char, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Empty\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 get_Length()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 Length\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Char get_Chars(Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsNullOrEmpty(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsNullOrWhiteSpace(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 CompareOrdinal(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 CompareOrdinal(System.String, Int32, System.String, Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Concat(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Concat(System.String, System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Concat(System.String, System.String, System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Concat(System.String[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean Contains(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean Equals(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean Equals(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 IndexOf(Char)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 IndexOf(Char, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 IndexOf(Char, Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 IndexOfAny(Char[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 IndexOfAny(Char[], Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 IndexOfAny(Char[], Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 LastIndexOf(Char)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 LastIndexOf(Char, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 LastIndexOf(Char, Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 LastIndexOfAny(Char[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 LastIndexOfAny(Char[], Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 LastIndexOfAny(Char[], Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Insert(Int32, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsNormalized()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Normalize()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Normalize(System.Text.NormalizationForm)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsNormalized(System.Text.NormalizationForm)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Join(System.String, System.String[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Join(System.String, System.String[], Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String PadLeft(Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String PadRight(Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String PadLeft(Int32, Char)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String PadRight(Int32, Char)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Remove(Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Remove(Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(Char, Char)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Substring(Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Substring(Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String ToLowerInvariant()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String ToUpperInvariant()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Trim()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Trim(Char[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String TrimEnd(Char[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String TrimStart(Char[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean op_Equality(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean op_Inequality(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var catalog = PureMemberCatalog.System.String;\n",
        "\n",
        "foreach (var member in catalog)\n",
        "{\n",
        "    Console.WriteLine(member);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Built-in catalogs are organized by namespace and type, so you could find the pure members on e.g. `Regex` as follows:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Void .ctor(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Void .ctor(System.String, System.Text.RegularExpressions.RegexOptions)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Void .ctor(System.String, System.Text.RegularExpressions.RegexOptions, System.TimeSpan)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.TimeSpan get_MatchTimeout()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.TimeSpan MatchTimeout\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.RegexOptions get_Options()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.RegexOptions Options\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean get_RightToLeft()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean RightToLeft\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Escape(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String GroupNameFromNumber(Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Int32 GroupNumberFromName(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsMatch(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsMatch(System.String, System.String, System.Text.RegularExpressions.RegexOptions)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsMatch(System.String, System.String, System.Text.RegularExpressions.RegexOptions, System.TimeSpan)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsMatch(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Boolean IsMatch(System.String, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.Match Match(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.Match Match(System.String, System.String, System.Text.RegularExpressions.RegexOptions)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.Match Match(System.String, System.String, System.Text.RegularExpressions.RegexOptions, System.TimeSpan)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.Match Match(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.Match Match(System.String, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.Match Match(System.String, Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.MatchCollection Matches(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.MatchCollection Matches(System.String, System.String, System.Text.RegularExpressions.RegexOptions)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.MatchCollection Matches(System.String, System.String, System.Text.RegularExpressions.RegexOptions, System.TimeSpan)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.MatchCollection Matches(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.Text.RegularExpressions.MatchCollection Matches(System.String, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String, System.String, System.Text.RegularExpressions.RegexOptions)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String, System.String, System.Text.RegularExpressions.RegexOptions, System.TimeSpan)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Replace(System.String, System.String, Int32, Int32)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String ToString()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "System.String Unescape(System.String)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "foreach (var member in PureMemberCatalog.System.Text.RegularExpressions.Regex)\n",
        "{\n",
        "    Console.WriteLine(member);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "In this context, purity means that the result of evaluating the member with its target instance (if any) and all of its arguments being constants will always produce the same result.\n",
        "\n",
        "Member catalogs are further structured such that one can obtain a catalog for an entire namespace, with or without including child namespaces. Some examples are shown below:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Pure member count in System = 943\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Pure member count on System.DateTimeOffset = 68\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Pure member count in System.Text.RegularExpressions = 74\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Pure member count on System.Text.RegularExpressions.Regex = 36\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Pure member count in System.Collections and all child namespaces = 5\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Total pure member count = 1022\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Console.WriteLine($\"Pure member count in System = {PureMemberCatalog.System.AllThisNamespaceOnly.Count()}\");\n",
        "Console.WriteLine($\"Pure member count on System.DateTimeOffset = {PureMemberCatalog.System.DateTimeOffset.Count()}\");\n",
        "Console.WriteLine($\"Pure member count in System.Text.RegularExpressions = {PureMemberCatalog.System.Text.RegularExpressions.AllThisNamespaceOnly.Count()}\");\n",
        "Console.WriteLine($\"Pure member count on System.Text.RegularExpressions.Regex = {PureMemberCatalog.System.Text.RegularExpressions.Regex.Count()}\");\n",
        "Console.WriteLine($\"Pure member count in System.Collections and all child namespaces = {PureMemberCatalog.System.Collections.AllThisAndChildNamespaces.Count()}\");\n",
        "Console.WriteLine($\"Total pure member count = {PureMemberCatalog.All.Count()}\");"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Member catalogs are immutable, but one can construct custom catalogs on top of existing ones, as shown below:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var myCatalog = new MemberTable\n",
        "{\n",
        "    PureMemberCatalog.All,\n",
        "    typeof(int).GetMethod(nameof(int.Parse), new[] { typeof(string) }),\n",
        "    typeof(string).GetMethod(nameof(string.ToUpper), Type.EmptyTypes),\n",
        "};"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Note that we've added `ToUpper` ourselves, because the default catalog doesn't consider this method to be pure either, because it does depend on the current culture. However, the default catalog does contain `Substring`, so we don't have to worry about that.\n",
        "\n",
        "Armed with this catalog, we can construct a `MetadataSemanticProvider` which inherits from `DefaultSemanticProvider` but provides properties that enable setting things such as the `PureMembers`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var sem = new MetadataSemanticProvider { PureMembers = myCatalog };\n",
        "var eval = new DefaultEvaluatorFactory();\n",
        "\n",
        "var opt = new ExpressionOptimizer(sem, eval);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "When we try to optimize our expression now, we'd expect to get a different result."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => \"foobarqux\".ToUpper().Substring(2, Parse(\"3\"))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => \"OBA\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Console.WriteLine(f);\n",
        "\n",
        "var optimized = opt.Visit(f);\n",
        "\n",
        "Console.WriteLine(optimized);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Indeed, the result is a single constant node containing the value `\"OBA\"` which is the result of evaluating `ToUpper`, `Substring`, and `Parse`.\n",
        "\n",
        "But what if the attempt to partially evaluate an expression causes an exception to be thrown? An example is shown below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => throw(System.ArgumentOutOfRangeException: startIndex cannot be larger than length of string. (Parameter 'startIndex')\r\n   at System.String.Substring(Int32 startIndex, Int32 length)\r\n   at lambda_method310(Closure , Object , Object ))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<string>> f = () => \"foobarqux\".ToUpper().Substring(10);\n",
        "\n",
        "var optimized = opt.Visit(f);\n",
        "\n",
        "Console.WriteLine(optimized);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This time, the expression gets rewritten to contain an `Expression.Throw` expression that will throw the exception that was encountered during partial evaluation at optimization time."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## A closer look at `ISemanticProvider`\n",
        "\n",
        "Semantic providers are used by the optimizer to gather semantic information about expressions, types, members, values, etc. The `ISemanticProvider` interface represents all the capabilities of a semantic provider.\n",
        "\n",
        "While custom implementations of this interface are possible, a good default choice for the semantic provider is `DefaultSemanticProvider` or `MetadataSemanticProvider`. The latter is more powerful because it supports specifying semantic information about .NET types and members, for example if a given type is immutable, or if a given member is a pure function. The library comes with various catalogs for commonly used types and members in the .NET Base Class Libraries, which can be used to construct a `MetadataSemanticProvider` as shown below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var msp = new MetadataSemanticProvider\n",
        "{\n",
        "    PureMembers = PureMemberCatalog.All,\n",
        "    ConstParameters = ConstParameterCatalog.All,\n",
        "    ImmutableTypes = ImmutableTypeCatalog.All\n",
        "};\n",
        "\n",
        "var opt = new ExpressionOptimizer(msp, new DefaultEvaluatorFactory());\n",
        "\n",
        "void Example(Expression expr)\n",
        "{\n",
        "    Console.WriteLine(expr);\n",
        "\n",
        "    var optimized = opt.Visit(expr);\n",
        "\n",
        "    Console.WriteLine(optimized);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Pure members\n",
        "\n",
        "We've already looked at pure members before. Pure members are used to perform partial evaluation of nodes such as `MethodCallExpression`, for example `Math.Abs(n)` where `n` itself is pure."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Abs(-2)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "2\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Example(Expression.Call(typeof(Math).GetMethod(nameof(Math.Abs), new[] { typeof(int) }), Expression.Constant(-2)));"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Constant parameters\n",
        "\n",
        "Constant parameters are required for partial evaluation of a function if any of its parameters has a mutable type but the function doesn't perform any mutation, e.g. `string.Split(string, char[])` doesn't mutate the given `char[]`. This makes the following optimization work."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "s => s.Split(new [] {,, ;})\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "s => s.Split(value(System.Char[]))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<string, string[]>> f = s => s.Split(',', ';');\n",
        "\n",
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The allocation of the `char[]` can now be avoided for every evaluation of the expression at runtime, because a single constant `char[]` is used. This is safe because we know that `Split` only reads from the array and never mutates its contents. If we have another custom API that exhibits this behavior, we can add it to the catalog as well. Let's first define such a method."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => Foo(\"qux\", new [] {1, 2, 3})\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => Foo(\"qux\", new [] {1, 2, 3})\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "class Bar\n",
        "{\n",
        "    public static string Foo(string s, params int[] xs) => s + \" = \" + string.Join(\",\", xs);\n",
        "}\n",
        "\n",
        "Expression<Func<string>> f = () => Bar.Foo(\"qux\", 1, 2, 3);\n",
        "\n",
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To add `Bar.Foo(int[])` to the catalog, we have to specify a pattern that indicates which parameter of `Foo` is to be treated as `const`. This is shown below:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var constParameterTable = new ParameterTable { ConstParameterCatalog.All };\n",
        "\n",
        "constParameterTable.Add<int[]>(xs => Bar.Foo(\"\", xs));\n",
        "\n",
        "msp = new MetadataSemanticProvider\n",
        "{\n",
        "    PureMembers = PureMemberCatalog.All,\n",
        "    ConstParameters = constParameterTable,\n",
        "    ImmutableTypes = ImmutableTypeCatalog.All\n",
        "};\n",
        "\n",
        "opt = new ExpressionOptimizer(msp, new DefaultEvaluatorFactory());"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "When we apply the optimizer this time, the `NewArrayInit` expression can get reduced to a constant as well."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => Foo(\"qux\", new [] {1, 2, 3})\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => Foo(\"qux\", value(System.Int32[]))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Note that if `Foo` itself would be marked as a pure member, the whole `Foo(\"qux\", 1, 2, 3)` expression could be evaluated during optimization. Let's demonstrate this to show how all of these optimizations can \"cascade\"."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var pureMemberTable = new MemberTable\n",
        "{\n",
        "    PureMemberCatalog.All,\n",
        "    typeof(Bar).GetMethod(nameof(Bar.Foo))\n",
        "};\n",
        "\n",
        "msp = new MetadataSemanticProvider\n",
        "{\n",
        "    PureMembers = pureMemberTable,\n",
        "    ConstParameters = constParameterTable,\n",
        "    ImmutableTypes = ImmutableTypeCatalog.All\n",
        "};\n",
        "\n",
        "opt = new ExpressionOptimizer(msp, new DefaultEvaluatorFactory());"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "When we apply the optimizer this time, the whole expression gets reduced to a constant."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => Foo(\"qux\", new [] {1, 2, 3})\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => \"qux = 1,2,3\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Immutable types\n",
        "\n",
        "Finally, checks for immutable types are used for various checks to ensure a member can't mutate the state of an object, e.g. `System.Tuple<T1, T2>` is immutable so it's safe to evaluate an instance of this type to a `Constant` such that subsequent calls can be made. Another well-known immutable type is `string`. For example, the reason that reducing `\"foo\".Substring(1).ToUpper()` to `\"oo\".ToUpper()` is because it's known that none of the members on `string` can cause mutation. Therefore, it's safe to have a `Constant` containing `\"oo\"` rather than evaluating `\"foo\".Substring(1)` every time to create a unique instance.\n",
        "\n",
        "To demonstrate this principle, we can use a custom record type in C# 9.0."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "record Person(string Name, int Age);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "A record is immutable, but the optimizer does have no notion of this. As such, if we try to construct an instance of `Person` given constant arguments, it does not know to optimize this to a constant. Let's show this below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => new Person(\"Bart\", 21).Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => new Person(\"Bart\", 21).Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<int>> f = () => new Person(\"Bart\", 21).Age;\n",
        "\n",
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "First, we can attempt to add the constructor of `Person` to the pure member catalog, as shown below:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var pureMemberTable = new MemberTable\n",
        "{\n",
        "    PureMemberCatalog.All,\n",
        "    typeof(Bar).GetMethod(nameof(Bar.Foo)),\n",
        "    typeof(Person).GetConstructor(new[] { typeof(string), typeof(int) })\n",
        "};\n",
        "\n",
        "msp = new MetadataSemanticProvider\n",
        "{\n",
        "    PureMembers = pureMemberTable,\n",
        "    ConstParameters = constParameterTable,\n",
        "    ImmutableTypes = ImmutableTypeCatalog.All\n",
        "};\n",
        "\n",
        "opt = new ExpressionOptimizer(msp, new DefaultEvaluatorFactory());"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "However, when we try to optimize the expression, we still are out of luck."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => new Person(\"Bart\", 21).Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => new Person(\"Bart\", 21).Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Even though the constructor is pure, the result of evaluating it would be a `ConstantExpression` containing a value of type `Person`. If `Person` were mutable, the optimization would be unsafe, because the shared instance could get mutated. We need to teach the semantic provider that `Person` is immutable, making it safe to share an instance."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var immutableTypes = new TypeTable\n",
        "{\n",
        "    ImmutableTypeCatalog.All,\n",
        "    typeof(Person)\n",
        "};\n",
        "\n",
        "msp = new MetadataSemanticProvider\n",
        "{\n",
        "    PureMembers = pureMemberTable,\n",
        "    ConstParameters = constParameterTable,\n",
        "    ImmutableTypes = immutableTypes\n",
        "};\n",
        "\n",
        "opt = new ExpressionOptimizer(msp, new DefaultEvaluatorFactory());"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This time aorund, optimization is more fruitful."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => new Person(\"Bart\", 21).Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => Person { Name = Bart, Age = 21 }.Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This may be subtle, but the `ToString` of the expression tree's `ConstantExpression` node is showing the result of calling `ToString` on `Person`, which reads as `Person { Name = Bart, Age = 21 }`. Obivously, we could take this one step further and let the optimizer know that `Name` and `Age` properties are pure as well, meaning that when evaluated on a constant `Person` instance, they will always return the same result."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "pureMemberTable.Add(typeof(Person).GetProperty(nameof(Person.Name)));\n",
        "pureMemberTable.Add(typeof(Person).GetProperty(nameof(Person.Age)));\n",
        "\n",
        "msp = new MetadataSemanticProvider\n",
        "{\n",
        "    PureMembers = pureMemberTable,\n",
        "    ConstParameters = constParameterTable,\n",
        "    ImmutableTypes = immutableTypes\n",
        "};\n",
        "\n",
        "opt = new ExpressionOptimizer(msp, new DefaultEvaluatorFactory());"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "And finally, we end up with the whole expression reducing to `21`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "() => new Person(\"Bart\", 21).Age\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => 21\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Example(f);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To show all of the optimizations combined, let's shown a more complex expression that involves an `InvocationExpression` of a `LambdaExpression` that prints a `Person` object."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Invoke(p => ((p.Name + \" is \") + p.Age.ToString()), new Person(\"Bart\", 21))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "(\"Bart is \" + 21.ToString())\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<Person, string>> toString = p => p.Name + \" is \" + p.Age.ToString();\n",
        "Expression<Func<Person>> newPerson = () => new Person(\"Bart\", 21);\n",
        "\n",
        "var e = Expression.Invoke(toString, newPerson.Body);\n",
        "\n",
        "Example(e);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Note that the optimizer got quite far in constant folding this fairly complex expression. The original expression looked like this:\n",
        "\n",
        "```csharp\n",
        "(p => (p.Name + \" is \") + p.Age.ToString())(new Person(\"Bart\", 21))\n",
        "```\n",
        "\n",
        "where the string concatenation was carried out in two steps and involving a boxing conversion for the age value.\n",
        "\n",
        "First, it knew that evaluating `new Person(\"Bart\", 21)` was safe to do, resulting in a `ConstantExpression`:\n",
        "\n",
        "```csharp\n",
        "(p => (p.Name + \" is \") + p.Age.ToString())(c)\n",
        "```\n",
        "\n",
        "where `c` is a constant containing `Person { Name = \"Bart\", Age = 21 }`.\n",
        "\n",
        "Next, this enabled inlining (also known as beta reduction) of the `Person` argument when invoking the `toString` lambda expression, so we ended up with:\n",
        "\n",
        "```csharp\n",
        "(c.Name + \" is \") + c.Age.ToString()\n",
        "```\n",
        "\n",
        "Because `Name` and `Age` are pure, this got further rewritten into:\n",
        "\n",
        "```csharp\n",
        "(\"Bart\" + \" is \") + 21.ToString()\n",
        "```\n",
        "\n",
        "The string concatenation operator for two `string` arguments is also considered pure in the default pure members catalog, so more constant evaluation took place:\n",
        "\n",
        "```csharp\n",
        "\"Bart is \" + 21.ToString()\n",
        "```\n",
        "\n",
        "And this is where the optimization ended, because `int.ToString()` is culture-sensitive and therefore not considered pure."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Evaluator factories\n",
        "\n",
        "Evaluator factories are used to perform partial evaluation of an expression tree, e.g. for a node whose behavior is pure and whose children are constants. An example of such an expression is shown below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "(3/5/2021 11:43:54 AM + 01:00:00)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var expr = Expression.Add(Expression.Constant(DateTime.Now), Expression.Constant(TimeSpan.FromHours(1)));\n",
        "\n",
        "Console.WriteLine(expr);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This node is a `BinaryExpression` of type `Add` where the `Method` refers to `op_Addition(DateTime, TimeSpan)` on `System.DateTime`. The default pure member catalog contains this method. If we run this expression through the optimizer, the evaluator factory is used to get a delegate that can evaluate this `+` operation given two constant operands. To illustrate this behavior, we'll implement `IEvaluatorFactory`, or rather inherit from `DefaultEvaluatorFactory` to add some logging."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "class MyEvaluatorFactory : DefaultEvaluatorFactory\n",
        "{\n",
        "    public override Delegate GetEvaluator(MethodInfo method)\n",
        "    {\n",
        "        var res = base.GetEvaluator(method);\n",
        "\n",
        "        Console.WriteLine($\"Got evaluator for {method}.\");\n",
        "\n",
        "        return res;\n",
        "    }\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Using the metadata semantic provider and the custome valuator factory, we can construct an expression optimizer instance."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var sem = new MetadataSemanticProvider { PureMembers = { PureMemberCatalog.All }, ImmutableTypes = { ImmutableTypeCatalog.All }, ConstParameters = { ConstParameterCatalog.All } };\n",
        "var eval = new MyEvaluatorFactory();\n",
        "\n",
        "var opt = new ExpressionOptimizer(sem, eval);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's now apply this optimizer to our expression and see the invocation to the evaluator."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Got evaluator for System.DateTime op_Addition(System.DateTime, System.TimeSpan).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "3/5/2021 12:43:54 PM\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var optimized = opt.Visit(expr);\n",
        "\n",
        "Console.WriteLine(optimized);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Note that the optimizer does not cache the delegates returned from the evaluator factory. This is done to avoid leaks, and one can perform caching within the evaluator factory instead. To show the lack of caching, we can apply the optimizer again to another expression."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Got evaluator for System.TimeSpan FromHours(Double).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Got evaluator for System.DateTime op_Addition(System.DateTime, System.TimeSpan).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "3/5/2021 1:45:54 PM\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<DateTime, double, DateTime>> addHours = (dt, hours) => dt + TimeSpan.FromHours(hours);\n",
        "\n",
        "var anotherExpr = Expression.Invoke(addHours, Expression.Constant(DateTime.Now), Expression.Constant(2.0));\n",
        "\n",
        "var anotherOptimizedExpr = opt.Visit(anotherExpr);\n",
        "\n",
        "Console.WriteLine(anotherOptimizedExpr);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "One way to provide caching at the evaluator factory level would be to use `Nuqleon.Memory`'s memoization support. An example of how to compose these pieces is shown below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "using System.Memory;\n",
        "\n",
        "class MyMemoizingEvaluatorFactory : MyEvaluatorFactory, IClearable\n",
        "{\n",
        "    private readonly IMemoizedDelegate<Func<MemberInfo, Delegate>> _memoizedGetEvaluator;\n",
        "\n",
        "    public MyMemoizingEvaluatorFactory(IMemoizationCacheFactory factory)\n",
        "    {\n",
        "        var mem = Memoizer.Create(factory);\n",
        "\n",
        "        _memoizedGetEvaluator = mem.Memoize<MemberInfo, Delegate>(base.GetEvaluator);\n",
        "    }\n",
        "\n",
        "    public override Delegate GetEvaluator(MemberInfo member)\n",
        "    {\n",
        "        return _memoizedGetEvaluator.Delegate(member);\n",
        "    }\n",
        "\n",
        "    public void Clear()\n",
        "    {\n",
        "        _memoizedGetEvaluator.Cache.Clear();\n",
        "    }\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "A real implementation would override a few more evaluator factory methods, but this suffices to demonstrate the effect by constructing a new optimizer that uses our memoizing evaluator factory. Also note that we're overriding `GetEvaluator(MemberInfo)` rather than the overload with `MethodInfo`. This is the entry-point method on the interface, so it allows for caching of evaluators of different member kinds (i.e. fields, properties, constructors, and methods)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "var sem = new MetadataSemanticProvider { PureMembers = { PureMemberCatalog.All }, ImmutableTypes = { ImmutableTypeCatalog.All }, ConstParameters = { ConstParameterCatalog.All } };\n",
        "\n",
        "var cacheFactory = ConcurrentMemoizationCacheFactory.CreateLru(16);\n",
        "var eval = new MyMemoizingEvaluatorFactory(cacheFactory);\n",
        "\n",
        "var opt = new ExpressionOptimizer(sem, eval);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "When we apply the optimizer to both expressions, we'll see the effects of caching."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Got evaluator for System.DateTime op_Addition(System.DateTime, System.TimeSpan).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Got evaluator for System.TimeSpan FromHours(Double).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "opt.Visit(expr);\n",
        "opt.Visit(anotherExpr);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "This time, we only see one call for `op_Addition`, as expected. Because our cache policy is set to LRU and to only contain 16 entries, we'll get a cap on the memory used.\n",
        "\n",
        "> **Note:** Many uses of expression optimizers in Reaqtor stacks use unbounded caches during optimization of a whole bunch of expressions trees, e.g. when trying to compact the expressions in a query engine. At the end of the optimization pass, the caches are cleared or simply dropped and garbage collected. Either way, the design of decoupling the optimizer from aspects such as semantic providers and evaluator factories allows for a great deal of flexibility and separation of concerns."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Customizing the `ExpressionOptimizer` by overriding `Visit` methods\n",
        "\n",
        "The behavior of the expression visitor can be influenced by overriding various `Visit` methods as well. Three customization points are worth mentioning:\n",
        "\n",
        "```csharp\n",
        "protected virtual bool ShouldOptimize(Expression node);\n",
        "\n",
        "protected virtual Expression VisitPreOptimize(Expression node);\n",
        "protected virtual Expression VisitPostOptimize(Expression original, Expression optimized);\n",
        "```\n",
        "\n",
        "In case it's undesirable for certain nodes to get optimized, one can override `ShouldOptimize`. Returning `false` from this method will cause the optimizer to stop traversing the given expression. Examples include retaining the exact shape of a `Quote` expression, or preventing any optimization for nodes of a certain `Type`. For example, if a node could get partially evaluated to a constant of some type `T` which is not supported by some serializer that will run post optimization, one can avoid that such constants end up in the tree. Alternatively, one could override `VisitPostOptimize` and return the original expression if a rewrite was undesirable. This enables a specialized optimizer to \"change its mind\".\n",
        "\n",
        "Rather than discussing all the possible ways these methods can be used, we'll just use them for logging in the example below. This also sheds some light on the optimizer's behavior."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [],
      "source": [
        "class LoggingExpressionOptimizer : ExpressionOptimizer\n",
        "{\n",
        "    private string _padLeft = \"\";\n",
        "\n",
        "    public LoggingExpressionOptimizer(ISemanticProvider semanticProvider, IEvaluatorFactory evaluatorFactory)\n",
        "        : base(semanticProvider, evaluatorFactory)\n",
        "    {\n",
        "    }\n",
        "\n",
        "    public override Expression Visit(Expression node)\n",
        "    {\n",
        "        Console.WriteLine($\"{_padLeft}{nameof(Visit)}({node}) \\r\\n{_padLeft}{{\");\n",
        "        Indent();\n",
        "        var res = base.Visit(node);\n",
        "        Outdent();\n",
        "        Console.WriteLine($\"{_padLeft}}} = {res}\");\n",
        "        return res;\n",
        "    }\n",
        "\n",
        "    protected override bool ShouldOptimize(Expression node)\n",
        "    {\n",
        "        var res = base.ShouldOptimize(node);\n",
        "        Console.WriteLine($\"{_padLeft}{nameof(ShouldOptimize)}({node}) = {res}\");\n",
        "        return res;\n",
        "    }\n",
        "\n",
        "    protected override Expression VisitPreOptimize(Expression node)\n",
        "    {\n",
        "        var res = base.VisitPreOptimize(node);\n",
        "        Console.WriteLine($\"{_padLeft}{nameof(VisitPreOptimize)}({node}) = {res}\");\n",
        "        return res;\n",
        "    }\n",
        "\n",
        "    protected override Expression VisitPostOptimize(Expression original, Expression optimized)\n",
        "    {\n",
        "        var res = base.VisitPostOptimize(original, optimized);\n",
        "        Console.WriteLine($\"{_padLeft}{nameof(VisitPostOptimize)}({original}, {optimized}) = {res}\");\n",
        "        return res;\n",
        "    }\n",
        "\n",
        "    private void Indent() => _padLeft = new string(' ', _padLeft.Length + 2);\n",
        "\n",
        "    private void Outdent() => _padLeft = new string(' ', _padLeft.Length - 2);\n",
        "}"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Let's just run our logging optimizer over an expression that will have a few rewrites."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Visit(() => (\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)) \r\n{\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  ShouldOptimize(() => (\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPreOptimize(() => (\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)) = () => (\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit((\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize((\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize((\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)) = (\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length) = \"foobarqux\".Substring(2, 3).ToUpperInvariant().Length\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(\"foobarqux\".Substring(2, 3).ToUpperInvariant()) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(\"foobarqux\".Substring(2, 3).ToUpperInvariant()) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(\"foobarqux\".Substring(2, 3).ToUpperInvariant()) = \"foobarqux\".Substring(2, 3).ToUpperInvariant()\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(\"foobarqux\".Substring(2, 3)) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(\"foobarqux\".Substring(2, 3)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(\"foobarqux\".Substring(2, 3)) = \"foobarqux\".Substring(2, 3)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(\"foobarqux\") \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(\"foobarqux\") = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(\"foobarqux\") = \"foobarqux\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = \"foobarqux\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(2) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(2) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(2) = 2\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = 2\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(3) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(3) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(3) = 3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = 3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Got evaluator for System.String Substring(Int32, Int32).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPostOptimize(\"foobarqux\".Substring(2, 3), \"oba\") = \"oba\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = \"oba\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Got evaluator for System.String ToUpperInvariant().\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPostOptimize(\"foobarqux\".Substring(2, 3).ToUpperInvariant(), \"OBA\") = \"OBA\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = \"OBA\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPostOptimize(\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length, 3) = 3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = 3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(1) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(1) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(1) = 1\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = 1\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPostOptimize((\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1), 4) = 4\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = 4\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPostOptimize(() => (\"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1), () => 4) = () => 4\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "} = () => 4\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "() => 4\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var opt = new LoggingExpressionOptimizer(sem, eval);\n",
        "\n",
        "Expression<Func<int>> f = () => \"foobarqux\".Substring(2, 3).ToUpperInvariant().Length + 1;\n",
        "\n",
        "var res = opt.Visit(f);\n",
        "\n",
        "Console.WriteLine(res);"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## More optimizations\n",
        "\n",
        "Besides partial evaluation and constant folding, the optimizer has a lot more optimization techniques under its belt. The list is quite long, so we'll limit ourselves to exploring a few of them here."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Branch analysis\n",
        "\n",
        "`ConditionalExpression` can be used for the conditional ternary operator `?:` as well as `if` statements. The expression optimizer can remove such branches if the condition evaluates to a constant. For example:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Visit(Invoke(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null), \"bar\")) \r\n{\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  ShouldOptimize(Invoke(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null), \"bar\")) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPreOptimize(Invoke(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null), \"bar\")) = Invoke(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null), \"bar\")\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)) = s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)) = IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(((s != null) AndAlso (s.Length > 0))) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(((s != null) AndAlso (s.Length > 0))) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(((s != null) AndAlso (s.Length > 0))) = ((s != null) AndAlso (s.Length > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit((s != null)) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize((s != null)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize((s != null)) = (s != null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(s) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(s) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(s) = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(null) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(null) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(null) = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = (s != null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit((s.Length > 0)) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize((s.Length > 0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize((s.Length > 0)) = (s.Length > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(s.Length) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(s.Length) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(s.Length) = s.Length\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            Visit(s) \r\n            {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "              ShouldOptimize(s) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "              VisitPreOptimize(s) = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            } = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = s.Length\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(0) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(0) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(0) = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = (s.Length > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = ((s != null) AndAlso (s.Length > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(Convert(s.get_Chars(0), Nullable`1)) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(Convert(s.get_Chars(0), Nullable`1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(Convert(s.get_Chars(0), Nullable`1)) = Convert(s.get_Chars(0), Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(s.get_Chars(0)) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(s.get_Chars(0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(s.get_Chars(0)) = s.get_Chars(0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(s) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(s) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(s) = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(0) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(0) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(0) = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = s.get_Chars(0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = Convert(s.get_Chars(0), Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(null) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(null) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(null) = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(s) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(s) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(s) = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = s\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(\"bar\") \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(\"bar\") = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(\"bar\") = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(IIF(((\"bar\" != null) AndAlso (\"bar\".Length > 0)), Convert(\"bar\".get_Chars(0), Nullable`1), null)) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(IIF(((\"bar\" != null) AndAlso (\"bar\".Length > 0)), Convert(\"bar\".get_Chars(0), Nullable`1), null)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(IIF(((\"bar\" != null) AndAlso (\"bar\".Length > 0)), Convert(\"bar\".get_Chars(0), Nullable`1), null)) = IIF(((\"bar\" != null) AndAlso (\"bar\".Length > 0)), Convert(\"bar\".get_Chars(0), Nullable`1), null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(((\"bar\" != null) AndAlso (\"bar\".Length > 0))) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(((\"bar\" != null) AndAlso (\"bar\".Length > 0))) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(((\"bar\" != null) AndAlso (\"bar\".Length > 0))) = ((\"bar\" != null) AndAlso (\"bar\".Length > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit((\"bar\" != null)) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize((\"bar\" != null)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize((\"bar\" != null)) = (\"bar\" != null)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(\"bar\") \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(\"bar\") = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(\"bar\") = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(null) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(null) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(null) = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Got evaluator for Boolean op_Inequality(System.String, System.String).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPostOptimize((\"bar\" != null), True) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit((\"bar\".Length > 0)) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize((\"bar\".Length > 0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize((\"bar\".Length > 0)) = (\"bar\".Length > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(\"bar\".Length) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(\"bar\".Length) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(\"bar\".Length) = \"bar\".Length\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(\"bar\") \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(\"bar\") = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(\"bar\") = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPostOptimize(\"bar\".Length, 3) = 3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = 3\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(0) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(0) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(0) = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPostOptimize((\"bar\".Length > 0), True) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPostOptimize(((\"bar\" != null) AndAlso (\"bar\".Length > 0)), True) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(Convert(\"bar\".get_Chars(0), Nullable`1)) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(Convert(\"bar\".get_Chars(0), Nullable`1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(Convert(\"bar\".get_Chars(0), Nullable`1)) = Convert(\"bar\".get_Chars(0), Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(\"bar\".get_Chars(0)) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(\"bar\".get_Chars(0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(\"bar\".get_Chars(0)) = \"bar\".get_Chars(0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(\"bar\") \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(\"bar\") = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(\"bar\") = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = \"bar\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(0) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(0) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(0) = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "Got evaluator for Char get_Chars(Int32).\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPostOptimize(\"bar\".get_Chars(0), b) = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPostOptimize(Convert(\"bar\".get_Chars(0), Nullable`1), b) = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(null) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(null) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(null) = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = null\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPostOptimize(IIF(((\"bar\" != null) AndAlso (\"bar\".Length > 0)), Convert(\"bar\".get_Chars(0), Nullable`1), null), b) = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPostOptimize(Invoke(s => IIF(((s != null) AndAlso (s.Length > 0)), Convert(s.get_Chars(0), Nullable`1), null), \"bar\"), b) = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "} = b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "b\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<string, char?>> getFirstChar = s => s != null && s.Length > 0 ? s[0] : null;\n",
        "\n",
        "var expr = Expression.Invoke(getFirstChar, Expression.Constant(\"bar\"));\n",
        "\n",
        "Console.WriteLine(opt.Visit(expr));"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "A lot is going on here. Let's break it down step by step. Our original expression is:\n",
        "\n",
        "\n",
        "```csharp\n",
        "(s => s => s != null && s.Length > 0 ? s[0] : null)(\"bar\")\n",
        "```\n",
        "\n",
        "First, there's beta reduction where the constant string got inlined in the lambda.\n",
        "\n",
        "```csharp\n",
        "\"bar\" != null && \"bar\".Length > 0 ? \"bar\"[0] : null\n",
        "```\n",
        "\n",
        "Next, the optimizer can determine that `\"bar\"` is never null. It knows that's the case of `new` expressions and a couple of other nodes, but also for constants it can inspect. In addition, it can ask the semantic provider whether an expression can never be null by using `IsNeverNull`.\n",
        "\n",
        "> **Note:** The optimizer predates the work on nullability analysis that was done in C# 8.0. A future revision of the optimizer could support much more nullability checks, e.g. for the return types of methods.\n",
        "\n",
        "Because `\"bar\"` can never be null, the expression can get reduced to:\n",
        "\n",
        "```csharp\n",
        "true && \"bar\".Length > 0 ? \"bar\"[0] : null\n",
        "```\n",
        "\n",
        "Rules for the binary `&&` operator enable dropping the `true` operand. (If the left operand were `false`, the expression optimizer would reduce the entire `&&` expression to `false`.) Now we have:\n",
        "\n",
        "```csharp\n",
        "\"bar\".Length > 0 ? \"bar\"[0] : null\n",
        "```\n",
        "\n",
        "Next, we're faced with a `MemberExpression` for `string.Length`, which results in a check for purity. Note there are more semantic questions asked, which we've never touched upon. In particular, the optimizer will check if the operand `IsAlwaysNull`. If so, it can directly emit code to `throw new NullReferenceException()`. Further optimizations of `TryExpression` nodes can also reason over exception flow. In this case, `\"bar\"` is never null, and `\"bar\".Length` will get evaluated to `3`. This can be seen in the output above, with a logging message indicating that the evaluator factory was consulted to build an evaluator for `(string s) => s.Length`, which then got passed `\"bar\"`. This results in:\n",
        "\n",
        "```csharp\n",
        "3 > 0 ? \"bar\"[0] : null\n",
        "```\n",
        "\n",
        "Partial evaluation of `3 > 0` results in `true`:\n",
        "\n",
        "```csharp\n",
        "true ? \"bar\"[0] : null\n",
        "```\n",
        "\n",
        "This in turn enables branch prediction, so we end up with:\n",
        "\n",
        "```csharp\n",
        "\"bar\"[0]\n",
        "```\n",
        "\n",
        "Once more, we have a pure member for the indexer of `string`, resulting in the construction of an evaluator, which finally results in:\n",
        "\n",
        "```csharp\n",
        "'b'\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Similar optimizations exist for `SwitchExpression` nodes where a `SwitchCase` \"arm\" of the expression can be predicted if the test value is a constant."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Inlining of invocations\n",
        "\n",
        "As we've seen in the samples before, the expression optimizer also knows how to inline `InvocationExpression` nodes applied to `LambdaExpression` operands. This form of beta reduction is only carried out if it's safe to do so, i.e. if side-effects would not get reordered or dropped on the floor. Beta reduction often occurs after binding template expressions with concrete parameter values. An example is shown below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Visit(Invoke((xs, a) => xs.Where(x => (x > a)), value(System.Int32[]), 0)) \r\n{\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  ShouldOptimize(Invoke((xs, a) => xs.Where(x => (x > a)), value(System.Int32[]), 0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPreOptimize(Invoke((xs, a) => xs.Where(x => (x > a)), value(System.Int32[]), 0)) = Invoke((xs, a) => xs.Where(x => (x > a)), value(System.Int32[]), 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit((xs, a) => xs.Where(x => (x > a))) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize((xs, a) => xs.Where(x => (x > a))) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize((xs, a) => xs.Where(x => (x > a))) = (xs, a) => xs.Where(x => (x > a))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(xs.Where(x => (x > a))) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(xs.Where(x => (x > a))) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(xs.Where(x => (x > a))) = xs.Where(x => (x > a))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit() \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(xs) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(xs) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(xs) = xs\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = xs\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(x => (x > a)) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(x => (x > a)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(x => (x > a)) = x => (x > a)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit((x > a)) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize((x > a)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize((x > a)) = (x > a)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(x) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(x) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(x) = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          Visit(a) \r\n          {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            ShouldOptimize(a) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "            VisitPreOptimize(a) = a\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          } = a\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = (x > a)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(x) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(x) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(x) = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = x => (x > a)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = xs.Where(x => (x > a))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(xs) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(xs) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(xs) = xs\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = xs\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(a) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(a) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(a) = a\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = a\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = (xs, a) => xs.Where(x => (x > a))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(value(System.Int32[])) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(value(System.Int32[])) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(value(System.Int32[])) = value(System.Int32[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = value(System.Int32[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(0) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(0) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(0) = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(value(System.Int32[]).Where(x => (x > 0))) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(value(System.Int32[]).Where(x => (x > 0))) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(value(System.Int32[]).Where(x => (x > 0))) = value(System.Int32[]).Where(x => (x > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit() \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(value(System.Int32[])) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(value(System.Int32[])) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(value(System.Int32[])) = value(System.Int32[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = value(System.Int32[])\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(x => (x > 0)) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(x => (x > 0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(x => (x > 0)) = x => (x > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit((x > 0)) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize((x > 0)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize((x > 0)) = (x > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(x) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(x) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(x) = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        Visit(0) \r\n        {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          ShouldOptimize(0) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "          VisitPreOptimize(0) = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        } = 0\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = (x > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(x) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(x) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(x) = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = x\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = x => (x > 0)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = value(System.Int32[]).Where(x => (x > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPostOptimize(Invoke((xs, a) => xs.Where(x => (x > a)), value(System.Int32[]), 0), value(System.Int32[]).Where(x => (x > 0))) = value(System.Int32[]).Where(x => (x > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "} = value(System.Int32[]).Where(x => (x > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "value(System.Int32[]).Where(x => (x > 0))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "Expression<Func<IEnumerable<int>, int, IEnumerable<int>>> query = (xs, a) => xs.Where(x => x > a);\n",
        "\n",
        "var boundQuery = Expression.Invoke(query, Expression.Constant(new[] { 1, 2, 3 }), Expression.Constant(0));\n",
        "\n",
        "Console.WriteLine(opt.Visit(boundQuery));"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Exception flow analysis\n",
        "\n",
        "As one final example, we'll consider a more complex statement tree to illustrate how the optimizer can reason over exception flow as well."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Visit(try { ... }) \r\n{\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  ShouldOptimize(try { ... }) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPreOptimize(try { ... }) = try { ... }\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(Convert((2147483647 + 1), Nullable`1)) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(Convert((2147483647 + 1), Nullable`1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(Convert((2147483647 + 1), Nullable`1)) = Convert((2147483647 + 1), Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit((2147483647 + 1)) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize((2147483647 + 1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize((2147483647 + 1)) = (2147483647 + 1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(2147483647) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(2147483647) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(2147483647) = 2147483647\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = 2147483647\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(1) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(1) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(1) = 1\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = 1\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPostOptimize((2147483647 + 1), throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method311(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)) = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method311(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method311(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPostOptimize(Convert((2147483647 + 1), Nullable`1), throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method311(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)) = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method311(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method311(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit() \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(default(Nullable`1)) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(default(Nullable`1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(default(Nullable`1)) = default(Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = default(Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit() \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit() \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPostOptimize(try { ... }, default(Nullable`1)) = default(Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "} = default(Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "default(Nullable`1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var expr =\n",
        "    Expression.TryCatch(\n",
        "        Expression.Convert(\n",
        "            Expression.AddChecked(Expression.Constant(int.MaxValue), Expression.Constant(1)),\n",
        "            typeof(int?)\n",
        "        ),\n",
        "        Expression.Catch(\n",
        "            typeof(OverflowException),\n",
        "            Expression.Default(typeof(int?))\n",
        "        )\n",
        "    );\n",
        "\n",
        "Console.WriteLine(opt.Visit(expr));"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "During optimization of the `+` operation with constant operands, partial evaluation triggered an `OverflowException`. This then caused the exception flow analysis to kick in, where the optimizer emulated the exception flow and ended up picking the `catch (OverflowException)` block, which returned a `default(int?)` expression. Even if this catch block would contain a non-trivial expression (e.g. `Console.WriteLine(\"Oops!\")`), the optimizer would be able to eliminate the whole `TryExpression` in favor of the catch block's body. A more complex example is shown here:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "dotnet_interactive": {
          "language": "csharp"
        }
      },
      "outputs": [
        {
          "data": {
            "text/plain": "Visit(try { ... }) \r\n{\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  ShouldOptimize(try { ... }) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPreOptimize(try { ... }) = try { ... }\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(WriteLine((2147483647 + 1))) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(WriteLine((2147483647 + 1))) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(WriteLine((2147483647 + 1))) = WriteLine((2147483647 + 1))\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit() \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit((2147483647 + 1)) \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize((2147483647 + 1)) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize((2147483647 + 1)) = (2147483647 + 1)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(2147483647) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(2147483647) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(2147483647) = 2147483647\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = 2147483647\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      Visit(1) \r\n      {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        ShouldOptimize(1) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "        VisitPreOptimize(1) = 1\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      } = 1\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPostOptimize((2147483647 + 1), throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method260(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)) = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method260(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method260(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPostOptimize(WriteLine((2147483647 + 1)), throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method260(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)) = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method260(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = throw(System.OverflowException: Arithmetic operation resulted in an overflow.\r\n   at lambda_method260(Closure , Object , Object )\r\n   at System.Linq.Expressions.ExpressionOptimizer.EvaluateBinary(BinaryExpression node, Func`3 evaluator, Object leftValue, Object rightValue) in D:\\Projects\\Reaqtive\\reaqtor\\Nuqleon\\Core\\LINQ\\Nuqleon.Linq.Expressions.Optimizers\\System\\Linq\\Expressions\\ExpressionOptimizer.Binary.cs:line 965)\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit() \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit(WriteLine(\"Oops!\")) \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    ShouldOptimize(WriteLine(\"Oops!\")) = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    VisitPreOptimize(WriteLine(\"Oops!\")) = WriteLine(\"Oops!\")\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit() \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    Visit(\"Oops!\") \r\n    {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      ShouldOptimize(\"Oops!\") = True\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "      VisitPreOptimize(\"Oops!\") = \"Oops!\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "    } = \"Oops!\"\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = WriteLine(\"Oops!\")\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit() \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  Visit() \r\n  {\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  } = \r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "  VisitPostOptimize(try { ... }, WriteLine(\"Oops!\")) = WriteLine(\"Oops!\")\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "} = WriteLine(\"Oops!\")\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        },
        {
          "data": {
            "text/plain": "WriteLine(\"Oops!\")\r\n"
          },
          "execution_count": 1,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "var expr =\n",
        "    Expression.TryCatch(\n",
        "        Expression.Call(\n",
        "            typeof(Console).GetMethod(nameof(Console.WriteLine), new[] { typeof(int) }),\n",
        "            Expression.AddChecked(Expression.Constant(int.MaxValue), Expression.Constant(1))\n",
        "        ),\n",
        "        Expression.Catch(\n",
        "            typeof(OverflowException),\n",
        "            Expression.Call(\n",
        "                typeof(Console).GetMethod(nameof(Console.WriteLine), new[] { typeof(string) }),\n",
        "                Expression.Constant(\"Oops!\")\n",
        "            )\n",
        "        )\n",
        "    );\n",
        "\n",
        "Console.WriteLine(opt.Visit(expr));"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "All of the logic that did the pure computation and triggered the exception was dropped and all that remains in a simple `Console.WriteLine(\"Oops!\");` statement.\n",
        "\n",
        "Obviously, this shows an extreme example of optimization where all the circumstances are just right to cause a massive reduction of the original expression. However, many of the optimization rules working in concert results in very powerful optimization capabilities."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".NET (C#)",
      "language": "C#",
      "name": ".net-csharp"
    },
    "language_info": {
      "file_extension": ".cs",
      "mimetype": "text/x-csharp",
      "name": "C#",
      "pygments_lexer": "csharp",
      "version": "9.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}